import gtk
import re, cPickle
import sys, os
import xml.dom.minidom as minidom
from xml.sax.saxutils import escape, unescape

possible_settings = ['keywords', 'qualifiers', 'layout', 'shortcuts', 'options']

class Settings:
    
    pattern = {
               'real':re.compile(r'(?<![\w%s])\d+\.\d+(?![\w%s])'%(re.escape(r'''.%&)]}#?\$'"'''), re.escape(r'''.%&([{#?\$'''))),
               'integer':re.compile(r'(?<![\w%s])\d+(?![\w.%s])'%(re.escape(r'''.%&)]}#?\$'"'''), re.escape(r'''.%&([{#?\$'''))),
               'variable':re.compile(r'(?<![\w.\&])[a-zA-Z_]\w*(?![\w\(])'),
               'function':re.compile(r'(?<![\w.\&])[a-zA-Z_]\w*(?=[\(])'),
               'string_qualifier':re.compile(r'''(?<!['"])("|'|"""|\'\'\')(?!['"])'''),
               'eos':re.compile(r'(?<![\s\\])\s*[\n|;]'),#end of statement
               'eol':re.compile(r'\s*\n'),#end of line
               'multiline':re.compile(r'\\\s*\n'),
               'assignment':re.compile(r'(?<!=)\s*=\s*(?!=)')
               }
    
    def __init__(self):
        self.maindir = os.path.dirname(os.path.abspath(__file__))+'/'
        self.activeProfile = None
        self.load_dirs()
        self.load()
    
    def refresh(self):
        pass
    
    def load(self):
        '''
        Loads all settings.
        '''
        
        self.profile = self.get_profile()
        for name in possible_settings:
            path = self.dirs[name]+self.profile[name]
            setattr(self, name, self.loadFromPath(path))
        self.refresh()
        
    def load_dirs(self):
        '''
        Loads the directories that are stored in the path.xml file and saves
        them to self.dirs.
        '''
         
        DOM = self._getdom(self.maindir+'paths.xml')
        mainElement = DOM.documentElement
        self.dirs = {}
        for element in mainElement.childNodes:
            if element.nodeType is not element.ELEMENT_NODE:
                continue
            for node in element.childNodes:
                if node.nodeType is not node.TEXT_NODE:
                    continue
                buf = node.data.strip(' \t\n')
                self.dirs[element.localName] = self._resolvePath(buf) 
    
    def get_profile(self, path = ''):
        '''
        Returns the default profile or, if path is given, the profile
        stored in path.
        '''
        
        if not path:
            path = self.dirs['profiles'] + self._getDefault(self.dirs['profiles'])
        DOM = self._getdom(path)
        mainElement = DOM.documentElement
        profile = {}
        for element in mainElement.childNodes:
            if element.nodeType is not element.ELEMENT_NODE:
                continue
            for node in element.childNodes:
                if node.nodeType is not node.TEXT_NODE:
                    continue
                profile[element.localName] = node.data.strip(' \t\n')
        return profile
    
    def loadFromPath(self, path):
        '''
        Loads a xml-setting document from path. Depending on the type of the
        document it gets further processed.
        '''
        
        path = self._resolvePath(path)
        DOM = self._getdom(path)
        mainElement = DOM.documentElement
        if mainElement.localName in possible_settings:
            #exec 'buf = self.get_'+mainElement.localName+'(mainElement)'
            buf = eval('self.get_'+mainElement.localName)(mainElement)
            return buf
    
    def _resolvePath(self, path):
        '''
        Converts relative Paths to absolute paths.
        '''
        
        if path[0]=='.':
            return os.path.normpath(str(self.maindir+path[1:]))+'/'
        else:
            return path
          
    def _getDefault(self, dir):
        '''
        Returns the default file, that is set in a text-file.
        '''
        
        f = open(dir + '/default.txt')
        buf = f.read().strip(' \t\n')
        f.close()
        return buf
    
    def getFiles(self, dir):
        '''
        Returns the path of all xml files that are in the directory.
        '''
        
        settingFiles = []
        paths = os.listdir(dir)
        for p in paths:
            longp = dir + p
            if os.path.isfile(longp) and os.path.splitext(p)[1]=='.xml':
                settingFiles.append(p)
        return settingFiles
    
    def _getdom(self, path):
        '''
        Returns the DOM representation of a setting file.
        '''
        
        #TODO: test for validity
        DOM = minidom.parse(path)
        return DOM
    
    def savedom(self, DOM, path):
        '''
        Saves a DOM to path.
        '''
        
        f = open(path, 'w')
        f.write(DOM.toxml())
        f.close()
    
    def get_options(self, mainElement):
        '''
        Returns all options stored in mainElement.
        '''
        
        options = {}
        for element in mainElement.childNodes:
            if element.nodeType != element.ELEMENT_NODE:
                continue
            for text in element.childNodes:
                if text.nodeType != text.TEXT_NODE:
                    continue
                options[element.localName] = text.data.strip(' \n\t')
        return options

            
    def get_keywords(self, mainElement):
        '''
        Returns all Keywords stored in mainElement.
        '''
        
        keytypes = {}
        #iterate over <sympyFunction>, <sympyMethod>, ...
        for keyType in mainElement.childNodes:
            if keyType.nodeType != keyType.ELEMENT_NODE:
                continue
            keywords = []
            keytypes[keyType.localName] = keywords
            #iterate over <sin>, <cos>, ...
            for key in keyType.childNodes:
                if key.nodeType != key.ELEMENT_NODE:
                    continue
                #iterate over text
                for entry in key.childNodes:
                    if entry.nodeType != entry.TEXT_NODE:
                        continue
                    identifier = entry.data.strip(' \n\t')
                    if identifier:
                        keywords.append((identifier, key.localName))
        return keytypes
    
    def get_qualifiers(self, mainElement):
        '''
        Returns all qualifiers stored in mainElement
        '''
        
        qualifiers = {}
        element = mainElement.getElementsByTagName('functionBracket')[0]
        start = element.getElementsByTagName('start')[0].childNodes[0].data.strip(' \n\t')
        end = element.getElementsByTagName('end')[0].childNodes[0].data.strip(' \n\t')
        qualifiers['functionBracket'] = (start, end)
        return qualifiers
    
    def get_layout(self, mainElement):
        '''
        Returns all layout quantities stored in mainElement
        TODO: implement load layout-settings
        '''
         
        pass
    
    def get_shortcuts(self, mainElement):
        '''
        Returns all shortcuts stored in mainElement.
        '''
        
        shortcuts = {}
        for element in mainElement.childNodes:
            if element.nodeType != element.ELEMENT_NODE:
                continue
            keyval, modifier = None, None
            flag = True
            for node in element.childNodes:
                if node.nodeType is not node.TEXT_NODE:
                    continue
                buf = unescape(node.data).strip(' \t\n')
                if buf:
                    flag = False
                    shortcuts[element.localName] = (gtk.accelerator_parse(buf))
            if flag:
                shortcuts[element.localName] = (0,0)
        return shortcuts
